// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/dns/dns_client.h"

#include <utility>

#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/rand_util.h"
#include "net/dns/address_sorter.h"
#include "net/dns/dns_config_service.h"
#include "net/dns/dns_session.h"
#include "net/dns/dns_socket_pool.h"
#include "net/dns/dns_transaction.h"
#include "net/log/net_log.h"
#include "net/socket/client_socket_factory.h"

namespace net {

namespace {

    class DnsClientImpl : public DnsClient {
    public:
        DnsClientImpl(NetLog* net_log,
            ClientSocketFactory* socket_factory,
            const RandIntCallback& rand_int_callback)
            : address_sorter_(AddressSorter::CreateAddressSorter())
            , net_log_(net_log)
            , socket_factory_(socket_factory)
            , rand_int_callback_(rand_int_callback)
        {
        }

        void SetConfig(const DnsConfig& config) override
        {
            factory_.reset();
            session_ = nullptr;
            if (config.IsValid() && !config.unhandled_options) {
                std::unique_ptr<DnsSocketPool> socket_pool(
                    config.randomize_ports
                        ? DnsSocketPool::CreateDefault(socket_factory_,
                            rand_int_callback_)
                        : DnsSocketPool::CreateNull(socket_factory_, rand_int_callback_));
                session_ = new DnsSession(config, std::move(socket_pool),
                    rand_int_callback_, net_log_);
                factory_ = DnsTransactionFactory::CreateFactory(session_.get());
            }
        }

        const DnsConfig* GetConfig() const override
        {
            return session_.get() ? &session_->config() : NULL;
        }

        DnsTransactionFactory* GetTransactionFactory() override
        {
            return session_.get() ? factory_.get() : NULL;
        }

        AddressSorter* GetAddressSorter() override { return address_sorter_.get(); }

    private:
        scoped_refptr<DnsSession> session_;
        std::unique_ptr<DnsTransactionFactory> factory_;
        std::unique_ptr<AddressSorter> address_sorter_;

        NetLog* net_log_;

        ClientSocketFactory* socket_factory_;
        const RandIntCallback rand_int_callback_;

        DISALLOW_COPY_AND_ASSIGN(DnsClientImpl);
    };

} // namespace

// static
std::unique_ptr<DnsClient> DnsClient::CreateClient(NetLog* net_log)
{
    return base::WrapUnique(
        new DnsClientImpl(net_log, ClientSocketFactory::GetDefaultFactory(),
            base::Bind(&base::RandInt)));
}

// static
std::unique_ptr<DnsClient> DnsClient::CreateClientForTesting(
    NetLog* net_log,
    ClientSocketFactory* socket_factory,
    const RandIntCallback& rand_int_callback)
{
    return base::WrapUnique(
        new DnsClientImpl(net_log, socket_factory, rand_int_callback));
}

} // namespace net
